//
// Created by LONG on 2020/10/18.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "assert.h"
#include "../../include/utils/fixRingBuffer.h"
#include "../../include/utils/memPool.h"

#define MP_ALIGN_SIZE (8)
#define MP_CHECK_FLAG_SIZE (4)

struct MemPool
{
    uint32_t type; /* 类型（SPSC、SPMC、MPSC、MPMC） */
    uint32_t chunkSize; /* 内存块大小 */
    uint32_t alignSize; /* 对齐后大小 */
    uint32_t capacity; /* 内存块个数 */
    void *buffer; /* 缓存首地址 */
    S_FixRingBuffer *ring; /* 用于维护内存块的队列 */
};

typedef struct
{
    void *chunk; /* 内存块地址 */
} S_MemElmnt;

typedef struct
{
    uint32_t check;
    uint32_t reqSize;
    S_MemPool *ower; /* 内存块所属的内存池 */
    const char* func;
    uint32_t line;
} S_MemBlockHead;

typedef struct
{
    uint32_t reserved; /* 预留给有效数据尾的检查标志 */
    uint32_t check;
} S_MemBlockTail;

S_MemPool *MP_Create(uint32_t count, uint32_t chunkSize, uint32_t type)
{
    uint32_t loop;
    size_t alignSize;
    S_MemPool *pool;
    void* block;
    S_MemElmnt elmnt;
    S_MemBlockHead *blockHead;
    S_MemBlockTail *blockTail;

/*
 *   4Byte  sizeof(void*)          chunkSize                 4Byte    4Byte
 *  ———————— ———————— —————————————————————————————————————— ———————— ————————
 * |  check | pool*  |                chunk                 |  rsv   | check  |
 *  ———————— ———————— —————————————————————————————————————— ———————— ————————
 * |   block head    |            block body                |   block tail    |
 */
    /* 头部(check)、真实数据尾(rsv)、尾部(check)各增加4字节越界检查，首部检查4字节后增加一个指向pool的指针 */
    alignSize = CALC_ALIGN_SIZE(chunkSize + sizeof(S_MemBlockHead) + sizeof(S_MemBlockTail), MP_ALIGN_SIZE);
    pool = OS_MemCalloc(1, sizeof(S_MemPool) + alignSize * count);
    if (NULL == pool)
    {
        return NULL;
    }

    /* 多预留8个空间 */
    pool->ring = FixRB_Create(NULL, count, sizeof(S_MemElmnt), type);
    if (NULL == pool->ring)
    {
        OS_MemFree(pool);
        return NULL;
    }

    pool->type = type;
    pool->chunkSize = chunkSize;
    pool->alignSize = alignSize;
    pool->capacity = count;
    pool->buffer = (char *)pool + sizeof(S_MemPool);

    for (loop = 0; loop < count; loop++)
    {
        block = (char *)pool->buffer + alignSize * loop;

        /* 在首部增加4字节越界检查标志 和 指向pool的指针*/
        blockHead = (S_MemBlockHead *)block;
        blockHead->check = MEM_CHECK_FLAG;
        blockHead->ower = pool;

        /* 在末尾增加4字节越界检查标志 */
        blockTail = (S_MemBlockTail *)((char *)block + sizeof(S_MemBlockHead) + chunkSize);
        blockTail->check = MEM_CHECK_FLAG;

        elmnt.chunk = (char *)block + sizeof(S_MemBlockHead);
        FixRB_Put(pool->ring, &elmnt, sizeof(elmnt));
    }

    MEMORY_BARRIER();

    return pool;
}

void MP_Destroy(S_MemPool *self)
{
    if (self == NULL)
    {
        return;
    }
    if (self->ring)
    {
        FixRB_Destroy(self->ring);
    }

    OS_MemFree(self);
}

void* MP_Get(S_MemPool *self, uint32_t size, const char* func, uint32_t line)
{
    int32_t ret;
    void* block;
    S_MemElmnt elmnt;
    uint32_t elmntSize;
    S_MemBlockHead *blockHead;
    S_MemBlockTail *blockTail;

    elmntSize = sizeof(elmnt);
    ret = FixRB_Get(self->ring, &elmnt, &elmntSize);
    if (unlikely(CSP_RC_OK != ret))
    {
        return NULL;
    }

    block = (char *)elmnt.chunk - sizeof(S_MemBlockHead);

    blockHead = (S_MemBlockHead *)block;
    MACRO_ASSERT(MEM_CHECK_FLAG == blockHead->check);

    blockHead->reqSize = size;
    blockHead->func = func;
    blockHead->line = line;

    *((uint32_t *)((char*)elmnt.chunk + size)) = MEM_CHECK_FLAG;

    blockTail = (S_MemBlockTail *)((char *)elmnt.chunk + self->chunkSize);
    MACRO_ASSERT(MEM_CHECK_FLAG == blockTail->check);

    return elmnt.chunk;
}

int32_t MP_Put(void *chunk)
{
    void* block;
    S_MemElmnt elmnt;
    S_MemBlockHead *blockHead;
    S_MemBlockTail *blockTail;

    block = (char *)chunk - sizeof(S_MemBlockHead);

    blockHead = (S_MemBlockHead *)block;
    MACRO_ASSERT(MEM_CHECK_FLAG == blockHead->check);

    MACRO_ASSERT(MEM_CHECK_FLAG == *((uint32_t *)((char*)chunk + blockHead->reqSize)));

    blockTail = (S_MemBlockTail *)((char *)chunk + blockHead->ower->chunkSize);
    MACRO_ASSERT(MEM_CHECK_FLAG == blockTail->check);

    blockHead->func = NULL;
    blockHead->line = 0;

    elmnt.chunk = chunk;
    return FixRB_Put(blockHead->ower->ring, &elmnt, sizeof(S_MemElmnt));
}

uint32_t MP_Count(S_MemPool *self)
{
    return FixRB_Count(self->ring);
}
